import { Subject } from 'rxjs';

// 对象选择控制，通过主键区分不同对象
export class MySelection<T extends Object> {
  store = new Map<T[keyof T], T>();
  change = new Subject<MySelection<T>>();
  selected: T[] = [];
  // 构造函数，传递主键，初始化数据和多选
  constructor(private primaryKey: keyof T, initData: Iterable<T> = [], public multiple = true) {
    this.select(...Array.from(initData));
    this.change.subscribe(() => (this.selected = Array.from(this.store.values())));
  }
  // 设置对象主键
  setPrimaryKey(key: keyof T) {
    this.primaryKey = key;
  }
  // 添加选择
  select(...values: T[]) {
    values.forEach(v => {
      if (!this.multiple) {
        this.store.clear();
      }
      if (v instanceof Array) {
        this.select(...v);
        return;
      }
      this.store.set(v[this.primaryKey], v);
    });
    this.change.next(this);
  }
  // 取消选择
  unselect(...values: T[]) {
    values.forEach(v => {
      this.store.delete(v[this.primaryKey]);
    });
    this.change.next(this);
  }
  // 触发选择，切换选中和非选中状态
  trigger(...values: T[]) {
    values.forEach(value => {
      if (this.isSelected(value)) {
        this.unselect(value);
      } else {
        this.select(value);
      }
    });
  }
  // 清空
  clear() {
    this.store.clear();
    this.change.next(this);
  }
  // 判断对象列表是否已选
  isSelected(...values: T[]) {
    return values.every(v => this.store.has(v[this.primaryKey]));
  }
  // 判断对象列表是否包含而非全选
  isUndetermined(...values: T[]) {
    return values.some(v => this.isSelected(v)) && !this.isSelected(...values);
  }
  // 返回已选对象主键列表
  keys<T = number>(): T[] {
    return [...this.store.keys()] as any;
  }
}
